<?php

class Request
{

	/**
	 * @var string
	 */
	public $response = null;

	/**
	 * @var bool
	 */
	protected $_executed = false;

	/**
	 * @var array
	 */
	protected $_params = array();

	/**
	 * @var string
	 */
	protected $_path = null;

	/**
	 * @var method
	 */
	protected $_method = null;

	/**
	 * process mode
	 * @var string
	 */
	protected $_amode = null;

	/**
	 * @var string
	 */
	protected $_bmode = null;

	/**
	 * process class
	 * @var string
	 */
	protected $_class = null;

	/**
	 * main request that instance current process
	 * @var Request
	 */
	static protected $_initiator = null;

	/**
	 * get main request
	 * @return Request
	 */
	static public function initiator()
	{
		if (null == self::$_initiator)
		{
			if (php_sapi_name() == 'cli')
			{
				self::$_initiator = new Request_Cli;
			}
			else
			{
				self::$_initiator = new Request_Http;
			}
		}
		return self::$_initiator;
	}

	/**
	 * Retrieve a member of the $_COOKIE superglobal
	 *
	 * If no $key is passed, returns the entire $_COOKIE array.
	 *
	 * @todo How to retrieve from nested arrays
	 * @param string $key
	 * @param mixed $default Default value to use if key not found
	 * @return mixed Returns null if key does not exist
	 */
	static public function getCookie($key = null, $default = null)
	{
		return null === $key ? $_COOKIE : (isset($_COOKIE[$key]) ? $_COOKIE[$key] : $default);
	}

	/**

	 * @param string $key
	 * @param string $default
	 * @return string
	 */
	static public function getServer($key = null, $default = null)
	{
		return null === $key ? $_SERVER : (isset($_SERVER[$key])) ? $_SERVER[$key] : $default;
	}

	/**
	 * @param string $key
	 * @param string $default
	 * @return string
	 */
	static public function getEnv($key = null, $default = null)
	{
		return null === $key ? $_ENV : (isset($_ENV[$key])) ? $_ENV[$key] : $default;
	}

	/**
	 * @param string $key
	 * @return string
	 */
	static public function getHeader($key)
	{

		// Try to get it from the $_SERVER array first
		$temp = 'HTTP_' . strtoupper(str_replace('-', '_', $key));

		if (isset($_SERVER[$temp]))
		{
			return $_SERVER[$temp];
		}

		if (function_exists('apache_request_headers'))
		{
			$headers = apache_request_headers();
			if (isset($headers[$key]))
			{
				return $headers[$key];
			}
			$header = strtolower($key);
			foreach ($headers as $k => $v)
			{
				if (strtolower($k) == $key)
				{
					return $value;
				}
			}
		}

		return false;
	}

	/**
	 * @return string
	 */
	static public function getScheme()
	{
		return self::getServer('HTTPS') == 'on' ? 'https' : 'http';
	}

	/**
	 * Get the HTTP host.
	 *
	 * "Host" ":" host [ ":" port ] ; Section 3.2.2
	 * Note the HTTP Host header is not the same as the URI host.
	 * It includes the port while the URI host doesn't.
	 *
	 * @return string
	 */
	static public function getHttpHost()
	{
		$host = self::getServer('HTTP_HOST');

		if (!empty($host))
		{
			return $host;
		}

		$scheme = self::getScheme();
		$name = self::getServer('SERVER_NAME');
		$port = self::getServer('SERVER_PORT');

		if (null === $name)
		{
			return '';
		}
		elseif (($scheme == 'http' && $port == 80) || ($scheme == 'https' && $port == 443))
		{
			return $name;
		}
		else
		{
			return $name . ':' . $port;
		}
	}

	/**
	 * @return string
	 */
	static public function getClientIp()
	{
		if (self::getServer('HTTP_CLIENT_IP'))
		{
			self::getServer('HTTP_CLIENT_IP');
		}

		if (self::getServer('HTTP_X_FORWARDED_FOR'))
		{
			return self::getServer('HTTP_X_FORWARDED_FOR');
		}

		return self::getServer('REMOTE_ADDR', '127.0.0.1');
	}

	/**
	 *
	 * @return boolean
	 */
	static public function isFlash()
	{
		return strpos(self::getHeader('USER_AGENT'), ' flash') !== false;
	}

	/**
	 * Is the request a Javascript XMLHttpRequest?
	 *
	 * Should work with Prototype/Script.aculo.us, possibly others.
	 *
	 * @return boolean
	 */
	static public function isAjax()
	{
		return (self::getHeader('X_REQUESTED_WITH') == 'XMLHttpRequest');
	}

	/**
	 * cosntructore
	 */
	public function __construct($path, $params = null, $method = 'GET')
	{
		$this -> _params = (array)$params;

		$this -> _path = $path;

		$this -> _method = strtoupper($method);

		$path = trim(str_replace('-', '', $path), '/');

		$arr = explode('/', $path);

		$module = 'core';

		if ($arr[0] == 'admin')
		{
			$this -> _amode = 'admin';
			if (isset($arr[1]))
			{
				$module = $arr[1];
				unset($arr[1]);
			}
		}
		else
		{
			$module = $arr[0];
			unset($arr[0]);
		}

		$sub = implode('_', array_map('ucfirst', $arr));

		$file = $module . '/class/action/' . str_replace('_', '/', strtolower($sub));

		if (file_exists($filename = SYSTEM_MODULE_PATH . '/' . $file . '.php'))
		{
			require_once $filename;
			$this -> _class = inflect($module) . '_Action_' . $sub;
		}
		else
		{
			throw new Agilet_Exception("request $path can not be exectuted!");
		}
	}

	/**
	 * @return bool
	 */
	public function __toString()
	{
		return $this -> response;
	}

	/**
	 * @param string $key
	 * @param mixed $default_value null
	 * @return mixed
	 */
	public function getParam($key, $default_value = NULL)
	{
		if (isset($this -> _params[$key]))
		{
			return $this -> _params[$key];
		}

		return $default_value = null;
	}

	/**
	 * @return array
	 */
	public function getParams()
	{
		return $this -> _params;
	}

	/**
	 * @return bool
	 */
	public function getGet()
	{
		return $_GET;
	}

	/**
	 * @return bool
	 */
	public function getPost()
	{
		return $_POST;
	}

	/**
	 * @return bool
	 */
	public function isPost()
	{
		return $this -> _method == 'POST';
	}

	/**
	 * @return bool
	 */

	public function isGet()
	{
		return $this -> _method == 'GET';
	}

	/**
	 * @return bool
	 */
	public function isPut()
	{
		return $this -> _method == 'PUT';
	}

	/**
	 * @return bool
	 */
	public function isHead()
	{
		return $this -> _method == 'HEAD';
	}

	/**
	 * @return bool
	 */
	public function isDelete()
	{
		return $this -> _method == 'DELETE';
	}

	/**
	 * dispatch a request
	 * @return Request
	 */
	public function execute($is_constroller = FALSE, $script = NULL)
	{

		if (!$this -> _executed)
		{

			$this -> _executed = true;

			// format path.

			$class = $this -> _class;

			$action = new $class;

			$action -> execute($this, $is_constroller, $script = NULL);

			$this -> _executed = TRUE;

			// manual unset action.
			unset($action);

		}
		return $this;
	}

	/**
	 * @return string
	 */
	public function getPath()
	{
		return $this -> _path;
	}

	/**
	 * @return string
	 */
	public function getMethod()
	{
		return $this -> _method;
	}

	static public function factory($path, $params = null)
	{
		return new Request($path, $params);
	}

}
